/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ext_dev.h"
#include "gpio_if.h"
#include "osal_irq.h"

#define IR_GPIO 3
#define IR_FALLING_TIMEOUT_TIME (5 * 1000)

typedef struct {
    ExtDevIrMontStsDef extDevIrMontSts;
    osTimerId_t irFallTimeoutTimerHandle;
    ExtDevIrStsNoticeCbDef extDevIrStsNoticeCb;
} ExtDevIrManageDef;

static ExtDevIrManageDef g_extDevIrManage = {
    .extDevIrMontSts = EXT_DEV_IR_NO_MAN,
    .irFallTimeoutTimerHandle = NULL,
    .extDevIrStsNoticeCb = NULL,
};

static int32_t ExtDevInterIrRisingIrqHandler(uint16_t gpio, void *data);

static void ExtDevInterIrFallTimeoutTimerCb(void *argument)
{
    (void)argument;
    g_extDevIrManage.extDevIrMontSts = EXT_DEV_IR_NO_MAN;
    if (NULL != g_extDevIrManage.extDevIrStsNoticeCb) {
        g_extDevIrManage.extDevIrStsNoticeCb(EXT_DEV_IR_NO_MAN);
    }
}

static int32_t ExtDevInterIrFallingIrqHandler(uint16_t gpio, void *data)
{
    if (gpio != IR_GPIO) {
        LOG_E("unexpected irq from gpio %d.", gpio);
        return HDF_FAILURE;
    }
    if (osOK != osTimerStart(g_extDevIrManage.irFallTimeoutTimerHandle, IR_FALLING_TIMEOUT_TIME)) {
        LOG_E("ir timer start failed!");
    }
    if (HDF_SUCCESS != GpioUnsetIrq(IR_GPIO, NULL)) {
        LOG_E("Unset ir gpio irq failed!");
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioSetIrq(IR_GPIO, OSAL_IRQF_TRIGGER_RISING, ExtDevInterIrRisingIrqHandler, NULL)) {
        LOG_E("Set ir gpio irq failed!");
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioEnableIrq(IR_GPIO)) {
        LOG_E("enable ir gpio irq failed!");
        GpioUnsetIrq(IR_GPIO, NULL);
        return EXT_DEV_ERROR;
    }
    return HDF_SUCCESS;
}

static int32_t ExtDevInterIrRisingIrqHandler(uint16_t gpio, void *data)
{
    if (gpio != IR_GPIO) {
        LOG_E("unexpected irq from gpio %d.", gpio);
        return HDF_FAILURE;
    }
    if (HDF_SUCCESS != GpioUnsetIrq(IR_GPIO, NULL)) {
        LOG_E("Unset ir gpio irq failed!");
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioSetIrq(IR_GPIO, OSAL_IRQF_TRIGGER_FALLING, ExtDevInterIrFallingIrqHandler, NULL)) {
        LOG_E("Set ir gpio irq failed!");
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioEnableIrq(IR_GPIO)) {
        LOG_E("enable ir gpio irq failed!");
        GpioUnsetIrq(IR_GPIO, NULL);
        return EXT_DEV_ERROR;
    }
    if (1 == osTimerIsRunning(g_extDevIrManage.irFallTimeoutTimerHandle)) {
        if (osOK != osTimerStop(g_extDevIrManage.irFallTimeoutTimerHandle)) {
            LOG_E("ir timer stop failed!");
        }
    }
    if ((EXT_DEV_IR_NO_MAN == g_extDevIrManage.extDevIrMontSts) && (NULL != g_extDevIrManage.extDevIrStsNoticeCb)) {
        g_extDevIrManage.extDevIrStsNoticeCb(EXT_DEV_IR_HAVE_MAN);
    }
    g_extDevIrManage.extDevIrMontSts = EXT_DEV_IR_HAVE_MAN;
    return HDF_SUCCESS;
}
/// 人体红外传感器初始化
ExtDevCtlRst ExtDevIrInit(ExtDevIrCfgDef extDevIrCfg)
{
    if (HDF_SUCCESS != GpioSetDir(IR_GPIO, GPIO_DIR_IN)) {
        LOG_E("Set ir dir in failed!");
        return EXT_DEV_ERROR;
    }
    LOG_I("extDevIrCfg.extDevIrWorkType = %d(0:EXT_DEV_IR_OBTAIN;1:EXT_DEV_IR_NOTICE).", extDevIrCfg.extDevIrWorkType);
    if (EXT_DEV_IR_NOTICE == extDevIrCfg.extDevIrWorkType) {
        if (NULL == extDevIrCfg.extDevIrStsNoticeCb) {
            LOG_E("Ir notice callback function is NULL!");
            return EXT_DEV_ERROR;
        }
        if (HDF_SUCCESS != GpioSetIrq(IR_GPIO, OSAL_IRQF_TRIGGER_RISING, ExtDevInterIrRisingIrqHandler, NULL)) {
            LOG_E("Set ir gpio irq failed!");
            return EXT_DEV_ERROR;
        }
        if (HDF_SUCCESS != GpioEnableIrq(IR_GPIO)) {
            LOG_E("enable ir gpio irq failed!");
            GpioUnsetIrq(IR_GPIO, NULL);
            return EXT_DEV_ERROR;
        }
        g_extDevIrManage.irFallTimeoutTimerHandle =
            osTimerNew(ExtDevInterIrFallTimeoutTimerCb, osTimerOnce, NULL, NULL);
        if (NULL == g_extDevIrManage.irFallTimeoutTimerHandle) {
            LOG_E("Reply ir(gpio%d) timer failed! ", IR_GPIO);
            return EXT_DEV_ERROR;
        }
        g_extDevIrManage.extDevIrStsNoticeCb = extDevIrCfg.extDevIrStsNoticeCb;
        LOG_I("extDevIrCfg.extDevIrStsNoticeCb = %x.", extDevIrCfg.extDevIrStsNoticeCb);
    } else if (EXT_DEV_IR_OBTAIN == extDevIrCfg.extDevIrWorkType) {
        // 主动获取方式不需要额外处理
    } else {
        LOG_E("Unexpect IR work type.");
        return EXT_DEV_ERROR;
    }
    return EXT_DEV_SUCCESS;
}
/// 人体红外传感器监测结果获取
ExtDevIrMontStsDef ExtDevGetIrMonSts(void)
{
    uint16_t val;
    if (0 != GpioRead(IR_GPIO, &val)) {
        LOG_E("GpioRead failed.");
    }
    return (val == GPIO_VAL_HIGH) ? EXT_DEV_IR_HAVE_MAN : EXT_DEV_IR_NO_MAN;
}